/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.codemanipulation; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; /** * This <code>ImportRewriteContext</code> is aware of all the types visible in * <code>compilationUnit</code> at <code>position</code>. * <p> * <b>Note:</b> This context only works if the AST was created with bindings! * </p> */ public class ContextSensitiveImportRewriteContext extends ImportRewriteContext { private final CompilationUnit fCompilationUnit; private final int fPosition; private IBinding[] fDeclarationsInScope; private Name[] fImportedNames; private final ImportRewrite fImportRewrite; /** * Creates an import rewrite context at the given node's start position. * * @param node the node to use as context * @param importRewrite the import rewrite * * @since 3.6 */ public ContextSensitiveImportRewriteContext(ASTNode node, ImportRewrite importRewrite) { this((CompilationUnit)node.getRoot(), node.getStartPosition(), importRewrite); } /** * Creates an import rewrite context at the given start position. * * @param compilationUnit the root * @param position the context position * @param importRewrite the import rewrite */ public ContextSensitiveImportRewriteContext(CompilationUnit compilationUnit, int position, ImportRewrite importRewrite) { fCompilationUnit= compilationUnit; fPosition= position; fImportRewrite= importRewrite; fDeclarationsInScope= null; fImportedNames= null; } @Override public int findInContext(String qualifier, String name, int kind) { IBinding[] declarationsInScope= getDeclarationsInScope(); for (int i= 0; i < declarationsInScope.length; i++) { if (declarationsInScope[i] instanceof ITypeBinding) { ITypeBinding typeBinding= (ITypeBinding)declarationsInScope[i]; if (isSameType(typeBinding, qualifier, name)) { return RES_NAME_FOUND; } else if (isConflicting(typeBinding, name)) { return RES_NAME_CONFLICT; } } else if (declarationsInScope[i] != null) { if (isConflicting(declarationsInScope[i], name)) { return RES_NAME_CONFLICT; } } } Name[] names= getImportedNames(); for (int i= 0; i < names.length; i++) { IBinding binding= names[i].resolveBinding(); if (binding instanceof ITypeBinding && !binding.isRecovered()) { ITypeBinding typeBinding= (ITypeBinding)binding; if (isConflictingType(typeBinding, qualifier, name)) { return RES_NAME_CONFLICT; } } } List<AbstractTypeDeclaration> list= fCompilationUnit.types(); for (Iterator<AbstractTypeDeclaration> iter= list.iterator(); iter.hasNext();) { AbstractTypeDeclaration type= iter.next(); ITypeBinding binding= type.resolveBinding(); if (binding != null) { if (isSameType(binding, qualifier, name)) { return RES_NAME_FOUND; } else { ITypeBinding decl= containingDeclaration(binding, qualifier, name); while (decl != null && !decl.equals(binding)) { int modifiers= decl.getModifiers(); if (Modifier.isPrivate(modifiers)) return RES_NAME_CONFLICT; decl= decl.getDeclaringClass(); } } } } String[] addedImports= fImportRewrite.getAddedImports(); String qualifiedName= JavaModelUtil.concatenateName(qualifier, name); for (int i= 0; i < addedImports.length; i++) { String addedImport= addedImports[i]; if (qualifiedName.equals(addedImport)) { return RES_NAME_FOUND; } else { if (isConflicting(name, addedImport)) return RES_NAME_CONFLICT; } } if (qualifier.equals("java.lang")) { //$NON-NLS-1$ //No explicit import statement required ITypeRoot typeRoot= fCompilationUnit.getTypeRoot(); if (typeRoot != null) { IPackageFragment packageFragment= (IPackageFragment) typeRoot.getParent(); try { ICompilationUnit[] compilationUnits= packageFragment.getCompilationUnits(); for (int i= 0; i < compilationUnits.length; i++) { ICompilationUnit cu= compilationUnits[i]; IType[] allTypes= cu.getAllTypes(); for (int j= 0; j < allTypes.length; j++) { IType type= allTypes[j]; String packageTypeName= type.getFullyQualifiedName(); if (isConflicting(name, packageTypeName)) return RES_NAME_CONFLICT; } } } catch (JavaModelException e) { } } } return fImportRewrite.getDefaultImportRewriteContext().findInContext(qualifier, name, kind); } private boolean isConflicting(String name, String importt) { int index= importt.lastIndexOf('.'); String importedName; if (index == -1) { importedName= importt; } else { importedName= importt.substring(index + 1, importt.length()); } if (importedName.equals(name)) { return true; } return false; } private ITypeBinding containingDeclaration(ITypeBinding binding, String qualifier, String name) { ITypeBinding[] declaredTypes= binding.getDeclaredTypes(); for (int i= 0; i < declaredTypes.length; i++) { ITypeBinding childBinding= declaredTypes[i]; if (isSameType(childBinding, qualifier, name)) { return childBinding; } else { ITypeBinding result= containingDeclaration(childBinding, qualifier, name); if (result != null) { return result; } } } return null; } private boolean isConflicting(IBinding binding, String name) { return binding.getName().equals(name); } private boolean isSameType(ITypeBinding binding, String qualifier, String name) { String qualifiedName= JavaModelUtil.concatenateName(qualifier, name); return binding.getQualifiedName().equals(qualifiedName); } private boolean isConflictingType(ITypeBinding binding, String qualifier, String name) { binding= binding.getTypeDeclaration(); return !isSameType(binding, qualifier, name) && isConflicting(binding, name); } private IBinding[] getDeclarationsInScope() { if (fDeclarationsInScope == null) { ScopeAnalyzer analyzer= new ScopeAnalyzer(fCompilationUnit); fDeclarationsInScope= analyzer.getDeclarationsInScope(fPosition, ScopeAnalyzer.METHODS | ScopeAnalyzer.TYPES | ScopeAnalyzer.VARIABLES); } return fDeclarationsInScope; } private Name[] getImportedNames() { if (fImportedNames == null) { IJavaProject project= null; IJavaElement javaElement= fCompilationUnit.getJavaElement(); if (javaElement != null) project= javaElement.getJavaProject(); List<SimpleName> imports= new ArrayList<SimpleName>(); ImportReferencesCollector.collect(fCompilationUnit, project, null, imports, null); fImportedNames= imports.toArray(new Name[imports.size()]); } return fImportedNames; } }